package me.flyray.crm.core.biz.customer;

import java.math.BigDecimal;
import java.util.Date;

import com.alibaba.fastjson.JSON;
import me.flyray.common.enums.*;
import me.flyray.common.exception.BusinessException;
import me.flyray.common.msg.ResponseCode;
import me.flyray.common.util.CurrencyUtils;
import me.flyray.common.util.SnowFlake;
import me.flyray.common.vo.PersonalOutPointResponse;
import me.flyray.common.vo.QueryPersonalAccountRequest;
import me.flyray.common.vo.QueryPersonalAccountResponse;
import me.flyray.crm.core.biz.personal.PersonalAccountBiz;
import me.flyray.crm.core.entity.*;
import me.flyray.crm.core.mapper.*;
import me.flyray.crm.facade.request.OutAccountRequest;
import me.flyray.crm.facade.request.UnfreezeAndOutAccountRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import me.flyray.common.util.EntityUtils;
import me.flyray.common.util.MD5;

import lombok.extern.slf4j.Slf4j;

/**
 * 个人或者商户解冻并出账接口
 */
@Slf4j
@Transactional(rollbackFor = Exception.class)
@Service
public class CustomerOutAccountBiz {

    @Value("${crm.account.balanceSaltValue}")
    private String balanceSaltValue;
    @Autowired
    private CustomerBaseMapper customerBaseMapper;
    @Autowired
    private MerchantAccountJournalMapper merchantAccountJournalMapper;
    @Autowired
    private MerchantAccountMapper merchantAccountMapper;
    @Autowired
    private UnfreezeJournalMapper unfreezeJournalMapper;
    @Autowired
    private PersonalAccountMapper personalAccountMapper;
    @Autowired
    private PersonalAccountJournalMapper personalAccountJournalMapper;
    @Autowired
    private PersonalAccountBiz personalAccountBiz;


    @Autowired
    private CustomerIntoAccountBiz customerIntoAccountBiz;

    /**
     * 个人或者商户解冻并出账接口
     * 若是商户：
     * 1.商户账户冻结金额扣除
     * 2.新增商户流水记录、解冻流水记录
     * 若是个人：
     * 1.个人账户冻结金额扣除
     * 2.新增个人账户流水记录、解冻流水记录
     */
    public void unfreezeAndOutAccount(UnfreezeAndOutAccountRequest unFreezeAndOutAccountRequest) {
        log.info("个人或者商户解冻并出账接口-请求参数：{}" + EntityUtils.beanToMap(unFreezeAndOutAccountRequest));
        /**
         * 根据冻结流水号查询是否被解冻
         * */
        //查询客户信息中的商户号和个人编号
        CustomerBase customerBase = new CustomerBase();
        customerBase.setPlatformId(unFreezeAndOutAccountRequest.getPlatformId());
        customerBase.setCustomerId(unFreezeAndOutAccountRequest.getCustomerId());
        customerBase = customerBaseMapper.selectOne(customerBase);

        UnfreezeJournal queryUnfreezeJournal = new UnfreezeJournal();
        queryUnfreezeJournal.setFreezeId(unFreezeAndOutAccountRequest.getFreezeId());
        UnfreezeJournal unfreezeJournal = unfreezeJournalMapper.selectOne(queryUnfreezeJournal);
        if (null != unfreezeJournal) {
            log.info("个人或者商户解冻并出账接口--冻结资金已解冻");
            throw new BusinessException(ResponseCode.UNFREEZE_IS_EXIST);
        }
        if (unFreezeAndOutAccountRequest.getCustomerType().equals(CustomerType.CUST_MERCHANT.getCode())) {
            MerchantAccount queryMerchantAccount = new MerchantAccount();
            queryMerchantAccount.setPlatformId(unFreezeAndOutAccountRequest.getPlatformId());
            queryMerchantAccount.setCustomerId(unFreezeAndOutAccountRequest.getCustomerId());
            queryMerchantAccount.setMerchantId(customerBase.getMerchantId());
            queryMerchantAccount.setMerchantType((unFreezeAndOutAccountRequest.getMerchantType()));
            queryMerchantAccount.setAccountType(unFreezeAndOutAccountRequest.getAccountType());
            MerchantAccount merchantAccount = merchantAccountMapper.selectOne(queryMerchantAccount);
            if (null != merchantAccount && merchantAccount.getStatus().equals(AccountState.normal.getCode())) {
//                if (!MD5.sign(CurrencyUtils.decimaltoString(merchantAccount.getAccountBalance()), balanceSaltValue, "utf-8").equals(merchantAccount.getCheckSum())) {
//                    log.info("个人或者商户解冻并出账接口-返回参数。。。。。。{}", merchantAccount);
//                    throw new BusinessException(ResponseCode.MER_ACC_BALANCE_NOT_MATE);
//                }
                //商户账户余额不足
                if (merchantAccount.getFreezeBalance().compareTo(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt())) < 0) {
                    log.info("个人或者商户解冻并出账接口-返回参数。。。。。。{}", merchantAccount);
                    throw new BusinessException(ResponseCode.MER_ACC_BALANCE_NOT_ENOUGH);
                }
                merchantAccount.setFreezeBalance(merchantAccount.getFreezeBalance().subtract(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt())));
                merchantAccount.setCheckSum(MD5.sign(CurrencyUtils.decimaltoString(merchantAccount.getAccountBalance()), balanceSaltValue, "utf-8"));
                merchantAccountMapper.updateByPrimaryKeySelective(merchantAccount);

                //如果交易类型是营收则往总交易账户增加交易金额
                if (TradeType.PAYRECEIPT.getCode().equals(unFreezeAndOutAccountRequest.getTradeType())) {
                    MerchantAccount totalAccount = new MerchantAccount();
                    totalAccount.setPlatformId(unFreezeAndOutAccountRequest.getPlatformId());
                    totalAccount.setCustomerId(unFreezeAndOutAccountRequest.getCustomerId());
                    totalAccount.setMerchantId(customerBase.getMerchantId());
                    totalAccount.setMerchantType(unFreezeAndOutAccountRequest.getMerchantType());
                    totalAccount.setAccountType(AccountType.TX_TOTAL.getCode());
                    MerchantAccount existTotalAccount = merchantAccountMapper.selectOne(totalAccount);
                    if (existTotalAccount == null) {
                        totalAccount.setAccountBalance(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt()));
                        totalAccount.setCheckSum(MD5.sign(totalAccount.getAccountBalance().toString(), balanceSaltValue, "utf-8"));
                        totalAccount.setUpdateTime(new Date());
                        merchantAccountMapper.insertSelective(totalAccount);
                    } else {
                        totalAccount.setAccountBalance(existTotalAccount.getAccountBalance().add(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt())));
                        totalAccount.setCheckSum(MD5.sign(existTotalAccount.getAccountBalance().toString(), balanceSaltValue, "utf-8"));
                        totalAccount.setUpdateTime(new Date());
                        merchantAccountMapper.updateByPrimaryKeySelective(totalAccount);
                    }
                }
            } else {
                log.info("个人或者商户解冻并出账接口--商户账户不存在或者被账户被冻结");
                throw new BusinessException(ResponseCode.MER_ACC_NOTEXIST);
            }
            MerchantAccountJournal merAccountJournal = new MerchantAccountJournal();
            merAccountJournal.setJournalId(String.valueOf(SnowFlake.getId()));
            merAccountJournal.setPlatformId(unFreezeAndOutAccountRequest.getPlatformId());
            merAccountJournal.setCustomerId(unFreezeAndOutAccountRequest.getMerchantId());
            merAccountJournal.setMerchantId(unFreezeAndOutAccountRequest.getMerchantId());
            merAccountJournal.setMerchantName(unFreezeAndOutAccountRequest.getMerchantName());
            merAccountJournal.setFromAccount(merchantAccount.getAccountId());
            merAccountJournal.setToAccount(unFreezeAndOutAccountRequest.getToAccount());
            merAccountJournal.setToAccountName(unFreezeAndOutAccountRequest.getToAccountName());
            merAccountJournal.setOrderNo(unFreezeAndOutAccountRequest.getOrderNo());
            //出账
            merAccountJournal.setInOutFlag(InOutFlag.out.getCode());
            merAccountJournal.setTradeAmt(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt()));
            merAccountJournal.setTradeType(unFreezeAndOutAccountRequest.getTradeType());
            merAccountJournal.setCreateTime(new Date());
            merAccountJournal.setRoleType(unFreezeAndOutAccountRequest.getRoleType());
            merchantAccountJournalMapper.insertSelective(merAccountJournal);
        }
        /**
         * 客户类型-若是个人 : 则需要个人账户余额增加、新增个人账户流水记录
         * */
        if (unFreezeAndOutAccountRequest.getCustomerType().equals(CustomerType.CUST_PERSONAL.getCode())) {
            PersonalAccount queryPersonalAccount = new PersonalAccount();
            queryPersonalAccount.setPlatformId(unFreezeAndOutAccountRequest.getPlatformId());
            queryPersonalAccount.setPersonalId(customerBase.getPersonalId());
            queryPersonalAccount.setAccountType(unFreezeAndOutAccountRequest.getAccountType());
            PersonalAccount personalAccount = personalAccountMapper.selectOne(queryPersonalAccount);
            if (null != personalAccount && personalAccount.getStatus().equals(AccountState.normal.getCode())) {
//                if (!MD5.sign(CurrencyUtils.decimaltoString(personalAccount.getAccountBalance()), balanceSaltValue, "utf-8").equals(personalAccount.getCheckSum())) {
//                    log.info("个人或者商户解冻并出账接口--个人账户余额不匹配");
//                    throw new BusinessException(ResponseCode.PER_ACC_BALANCE_NOT_MATE);
//                }
                personalAccount.setFreezeBalance(personalAccount.getFreezeBalance().subtract(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt())));
                personalAccountMapper.updateByPrimaryKeySelective(personalAccount);
            } else {
                log.info("个人或者商户解冻并出账接口--个人账户不存在或者被冻结");
                throw new BusinessException(ResponseCode.PER_ACC_NOTEXIST);
            }
            PersonalAccountJournal personalAccountJournal = new PersonalAccountJournal();
            personalAccountJournal.setJournalId(String.valueOf(SnowFlake.getId()));
            personalAccountJournal.setPlatformId(unFreezeAndOutAccountRequest.getPlatformId());
            personalAccountJournal.setPersonalId(customerBase.getPersonalId());
            personalAccountJournal.setAccountId(personalAccount.getAccountId());
            personalAccountJournal.setAccountType(personalAccount.getAccountType());
            personalAccountJournal.setOrderNo(unFreezeAndOutAccountRequest.getOrderNo());
            //来往标志  1：入账   2：出账
            personalAccountJournal.setInOutFlag(InOutFlag.out.getCode());
            personalAccountJournal.setTradeAmt(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt()));
            //交易类型（支付:01，退款:02，提现:03，充值:04）
            personalAccountJournal.setTradeType(unFreezeAndOutAccountRequest.getTradeType());
            personalAccountJournal.setCreateTime(new Date());
            personalAccountJournalMapper.insertSelective(personalAccountJournal);
        }
        /***
         * 新增解冻流水记录
         * */
        queryUnfreezeJournal.setJournalId(String.valueOf(SnowFlake.getId()));
        queryUnfreezeJournal.setOrderNo(unFreezeAndOutAccountRequest.getOrderNo());
        //交易类型（支付:01，退款:02，提现:03，充值:04）
        queryUnfreezeJournal.setTradeType(unFreezeAndOutAccountRequest.getTradeType());
        queryUnfreezeJournal.setUnfreezeBalance(new BigDecimal(unFreezeAndOutAccountRequest.getUnfreezeAmt()));
        queryUnfreezeJournal.setCreateTime(new Date());
        unfreezeJournalMapper.insertSelective(queryUnfreezeJournal);
    }

    /**
     * 个人或者商户直接出账接口
     * 若是商户:
     * 1.商户账户余额扣除，2.新增商户账户流水
     * 若是个人:
     * 1.个人账户余额扣除  2.新增个人账户流水
     */
    public void outAccount(OutAccountRequest outAccountRequest) {
        log.info("个人或者商户直接出账接口-请求参数：{}" + EntityUtils.beanToMap(outAccountRequest));

        //查询客户信息中的商户号和个人编号
        CustomerBase customerBase = new CustomerBase();
        customerBase.setPlatformId(outAccountRequest.getPlatformId());
        customerBase.setCustomerId(outAccountRequest.getCustomerId());
        customerBase = customerBaseMapper.selectOne(customerBase);

        if (outAccountRequest.getCustomerType().equals(CustomerType.CUST_MERCHANT.getCode())) {
            /**
             * 修改商户账户余额
             * */
            MerchantAccount queryMerchantAccount = new MerchantAccount();
            queryMerchantAccount.setPlatformId(outAccountRequest.getPlatformId());
            queryMerchantAccount.setMerchantId(customerBase.getMerchantId());
            queryMerchantAccount.setMerchantType(outAccountRequest.getMerchantType());
            queryMerchantAccount.setAccountType(outAccountRequest.getAccountType());
            MerchantAccount merchantAccount = merchantAccountMapper.selectOne(queryMerchantAccount);
            if (null != merchantAccount && merchantAccount.getStatus().equals(AccountState.normal.getCode())) {
                //校验商户账户余额是否匹配  和商户账户余额是否充足
//                if (!MD5.sign(CurrencyUtils.decimaltoString(merchantAccount.getAccountBalance()), balanceSaltValue, "utf-8").equals(merchantAccount.getCheckSum())) {
//                    throw new BusinessException(ResponseCode.MER_ACC_BALANCE_NOT_MATE);
//                }
                if (merchantAccount.getAccountBalance().compareTo(new BigDecimal(outAccountRequest.getOutAccAmt())) < 0) {
                    log.info("个人或者商户直接出账接口 返回参数。。。。。。{}", merchantAccount);
                    throw new BusinessException(ResponseCode.MER_ACC_BALANCE_NOT_ENOUGH);
                }
                BigDecimal newBlance = merchantAccount.getAccountBalance().subtract(new BigDecimal(outAccountRequest.getOutAccAmt()));
                merchantAccount.setAccountBalance(newBlance);
                merchantAccount.setCheckSum(MD5.sign(newBlance.toString(), balanceSaltValue, "utf-8"));
                merchantAccountMapper.updateByPrimaryKeySelective(merchantAccount);
            } else {
                log.info("个人或者商户直接出账接口--商户账户不存在或者被冻结");
                throw new BusinessException(ResponseCode.MER_ACC_NOTEXIST);
            }
            /***
             * 新增商户账户流水记录
             * */
            MerchantAccountJournal merAccountJournal = new MerchantAccountJournal();
            merAccountJournal.setJournalId(String.valueOf(SnowFlake.getId()));
            merAccountJournal.setPlatformId(outAccountRequest.getPlatformId());
            merAccountJournal.setMerchantId(customerBase.getMerchantId());
//            merAccountJournal.setMerchantName(customerBase.);
            merAccountJournal.setFromAccount(merchantAccount.getAccountId());
            merAccountJournal.setOrderNo(outAccountRequest.getOrderNo());
            merAccountJournal.setAccountType(outAccountRequest.getAccountType());
            merAccountJournal.setCustomerId(outAccountRequest.getCustomerId());
            merAccountJournal.setFromAccountName(outAccountRequest.getAccountName());
            //出账
            merAccountJournal.setInOutFlag(InOutFlag.out.getCode());
            merAccountJournal.setTradeAmt(new BigDecimal(outAccountRequest.getOutAccAmt()));
            //交易类型（支付:01，退款:02，提现:03，充值:04）
            merAccountJournal.setTradeType(outAccountRequest.getTradeType());
            merAccountJournal.setCreateTime(new Date());
            merAccountJournal.setRoleType(outAccountRequest.getRoleType());
            merchantAccountJournalMapper.insertSelective(merAccountJournal);
        }

        if (outAccountRequest.getCustomerType().equals(CustomerType.CUST_PERSONAL.getCode())) {
            PersonalAccount queryPersonalAccount = new PersonalAccount();
            queryPersonalAccount.setPlatformId(outAccountRequest.getPlatformId());
            queryPersonalAccount.setPersonalId(customerBase.getPersonalId());
            queryPersonalAccount.setAccountType(outAccountRequest.getAccountType());
            PersonalAccount personalAccount = personalAccountMapper.selectOne(queryPersonalAccount);
            if (null != personalAccount && personalAccount.getStatus().equals(AccountState.normal.getCode())) {
//                if (!MD5.sign(personalAccount.getAccountBalance().toString(), balanceSaltValue, "utf-8").equals(personalAccount.getCheckSum())) {
//                    log.info("个人或者商户直接出账接口 返回参数。。。。。。{}", personalAccount);
//                    throw new BusinessException(ResponseCode.PER_ACC_BALANCE_NOT_MATE);
//                }
                personalAccount.setAccountBalance(personalAccount.getAccountBalance().subtract(new BigDecimal(outAccountRequest.getOutAccAmt())));
                personalAccount.setCheckSum(MD5.sign(personalAccount.getAccountBalance().toString(), balanceSaltValue, "utf-8"));
                personalAccountMapper.updateByPrimaryKeySelective(personalAccount);
            } else {
                log.info("个人或者商户直接出账接口--个人账户不存在或者被冻结");
                throw new BusinessException(ResponseCode.PER_ACC_NOTEXIST);
            }
            /***
             * 新增个人账户流水记录
             * */
            PersonalAccountJournal personalAccountJournal = new PersonalAccountJournal();
            personalAccountJournal.setJournalId(String.valueOf(SnowFlake.getId()));
            personalAccountJournal.setPlatformId(outAccountRequest.getPlatformId());
            personalAccountJournal.setPersonalId(customerBase.getPersonalId());
            personalAccountJournal.setAccountId(personalAccount.getAccountId());
            personalAccountJournal.setAccountType(personalAccount.getAccountType());
            personalAccountJournal.setOrderNo(outAccountRequest.getOrderNo());
            //来往标志  1：入账   2：出账
            personalAccountJournal.setInOutFlag(InOutFlag.out.getCode());
            personalAccountJournal.setTradeAmt(new BigDecimal(outAccountRequest.getOutAccAmt()));
            //交易类型（支付:01，退款:02，提现:03，充值:04）
            personalAccountJournal.setTradeType(outAccountRequest.getTradeType());
            personalAccountJournal.setCreateTime(new Date());
//            personalAccountJournal.setRoleType(outAccountRequest.getRoleType());
            personalAccountJournalMapper.insertSelective(personalAccountJournal);
        }
    }

    @Transactional
    public PersonalOutPointResponse personnalPointOutAccount(OutAccountRequest outAccountRequest) {
        log.info("个人或者商户直接出账接口-请求参数：{}" + EntityUtils.beanToMap(outAccountRequest));
        //查询积分账户余额
        QueryPersonalAccountRequest queryPersonalAccount = new QueryPersonalAccountRequest();
        queryPersonalAccount.setPlatformId(outAccountRequest.getPlatformId());
        queryPersonalAccount.setPersonalId(outAccountRequest.getPersonalId());
        //TODO 后面考虑锁保证扣减的原子性
        //判断用户的积分余额
        PersonalPointAccount personalAccount = personalAccountMapper.selectPointAccount(queryPersonalAccount);
        PersonalAccountJournal personalAccountJournal = new PersonalAccountJournal();
        //判断历史积分账户是否可以抵扣
        PersonalAccount condition = new PersonalAccount();
        if (personalAccount.getHisPoint().intValue() >= Integer.valueOf(outAccountRequest.getOutAccAmt())) {
            condition.setAccountType(AccountType.HIS_POINT.getCode());
        } else if (personalAccount.getPoint().intValue() >= Integer.valueOf(outAccountRequest.getOutAccAmt())) {
            condition.setAccountType(AccountType.POINT.getCode());
        } else {
            //TODO
        }

        condition.setPersonalId(outAccountRequest.getPersonalId());
        condition.setPlatformId(outAccountRequest.getPlatformId());
        condition = personalAccountMapper.selectOne(condition);
        if (condition == null) {
            throw new BusinessException(ResponseCode.PER_ACC_NOTEXIST);
        }
        //更新余额账户
        BigDecimal balance = condition.getAccountBalance();
        balance.subtract(new BigDecimal(outAccountRequest.getOutAccAmt()));
        condition.setAccountBalance(balance);
        personalAccountMapper.updateByPrimaryKeySelective(condition);
        personalAccountJournal.setAccountType(condition.getAccountType());

        /***
         * 新增个人账户流水记录
         * */
        addPersonalJournal(personalAccountJournal, outAccountRequest, condition);
        //获取个人账户

        QueryPersonalAccountRequest queryPersonalAccountRequest = new QueryPersonalAccountRequest();
        queryPersonalAccountRequest.setPersonalId(outAccountRequest.getPersonalId());
        queryPersonalAccountRequest.setPlatformId(outAccountRequest.getPlatformId());
        QueryPersonalAccountResponse queryPersonalAccountResponse = personalAccountBiz.queryPersonalAcount(queryPersonalAccountRequest);
        return assembly(queryPersonalAccountResponse,personalAccountJournal.getJournalId());
    }

    private PersonalOutPointResponse assembly(QueryPersonalAccountResponse queryPersonalAccountResponse, String journalId) {
        PersonalOutPointResponse personalOutPointResponse = new PersonalOutPointResponse();
        personalOutPointResponse.setHisPoint(queryPersonalAccountResponse.getHisPoint());
        personalOutPointResponse.setId(queryPersonalAccountResponse.getId());
        personalOutPointResponse.setJournalId(journalId);
        personalOutPointResponse.setPersonalId(queryPersonalAccountResponse.getPersonalId());
        personalOutPointResponse.setPoint(queryPersonalAccountResponse.getPoint());
        personalOutPointResponse.setTotalPoint(queryPersonalAccountResponse.getTotalPoint());
        return personalOutPointResponse;
    }

    private void addPersonalJournal(PersonalAccountJournal personalAccountJournal, OutAccountRequest outAccountRequest, PersonalAccount personalAccount) {
        personalAccountJournal.setJournalId(String.valueOf(SnowFlake.getId()));
        personalAccountJournal.setPersonalId(outAccountRequest.getPersonalId());
        personalAccountJournal.setAccountId(personalAccount.getAccountId());
        personalAccountJournal.setOrderNo(outAccountRequest.getOrderNo());
        personalAccountJournal.setInOutFlag(InOutFlag.out.getCode());
        personalAccountJournal.setTradeAmt(new BigDecimal(outAccountRequest.getOutAccAmt()));
        personalAccountJournal.setTradeType(outAccountRequest.getTradeType());
        personalAccountJournal.setCreateTime(new Date());
        personalAccountJournal.setPlatformId(outAccountRequest.getPlatformId());
        int i = personalAccountJournalMapper.insertSelective(personalAccountJournal);
        if (i != 1) {
            log.info("addPersonalJournal invalid .. {}", JSON.toJSONString(personalAccountJournal));
        }
    }

}
